/*
 *文件作用: 声明内部类型和API实现
 */

#include "leptjson.h"
#include <assert.h>
#include <errno.h>  //error, ERANGE
#include <malloc.h>
#include <math.h>  // HUGE_VAL
#include <stdio.h>
#include <stdlib.h>  //NULL, strtod()
#include <string.h>

#ifndef LEPT_PARSE_STACK_INIT_SIZE
#    define LEPT_PARSE_STACK_INIT_SIZE 256  //缓冲栈初始大小 (单位: byte)
#endif

//将字符放入缓冲栈
//注意这里 lept_context_stack_grow(context, sizeof((char)ch)) 中, 会伴随整型提升必须用 (char) 强制转换回int
//的隐式类型转换
#define PUTC(context, ch)                                                                                              \
    do {                                                                                                               \
        *(char*)lept_context_stack_grow(context, sizeof((char)(ch))) = (char)(ch);                                     \
    } while (0)

//把一个字节压入缓冲栈, 要求作用域内已有 leptcontext* c
#define OutPutByte(byte) PUTC(c, (char)byte)

#define PRINTSTACK(pcontext, byte)                                                                                     \
    do {                                                                                                               \
        const __uint8_t* p = (__uint8_t*)pcontext->stack;                                                              \
        size_t i = 0;                                                                                                  \
        for (i = 0; i < len; ++i) {                                                                                    \
            __uint8_t tmp = *(p++);                                                                                    \
            printf("%x ", tmp);                                                                                        \
        }                                                                                                              \
    } while (0)

//将json的相关数据封装，减少解析函数之间传递的参数个数
//暂只存放json字符串
typedef struct {
    size_t size;  //堆栈大小
    size_t top;   //堆栈栈顶位置
    const char* json;
    char* stack;  //缓冲区堆栈
} lept_context;

//释放节点空间, 将类型重置为 LEPT_NULL
void lept_free(lept_value* v) {
    assert(v != NULL);
    if (v->type == LEPT_STRING) {
        free(v->union_struct.str.string);
    }
    v->union_struct.str.length = 0;
    v->type == LEPT_NULL;
}

//让缓冲栈增长指定空间, 返回指向下一个可用空间的指针
void* lept_context_stack_grow(lept_context* c, size_t appended_size) {
    void* ret = NULL;
    assert(appended_size > 0);

    //若增长后会超过现有缓冲栈大小, 则必须重新为缓冲栈分配空间
    if (c->top + appended_size >= c->size) {
        //如果当前缓冲栈大小为0, 则直接分配一个初始空间即可
        if (c->size == 0) {
            c->size = LEPT_PARSE_STACK_INIT_SIZE;
        }

        //如果现有缓冲栈空间不足以支持增长, 则增长至现有空间的 1.5 倍,
        //若仍不足则继续重复增长
        while (c->top + appended_size >= c->size) {
            c->size += (c->size >> 1);
        }
    }

    char* tmp_ptr = (char*)realloc(c->stack, c->size);  //确定重新分配的大小后, 申请重新分配内存
    if (!tmp_ptr) {
        return 0;
    }
    c->stack = tmp_ptr;
    // printf("\nBefore append ==> context->top == %d\n", c->top);
    c->top += appended_size;  //栈顶位置增长, 增量等同于 appended_size
    // printf("\nAfter append ==> context->top == %d\n", c->top);
    ret = c->stack + c->top - (size_t)1;  //返回栈顶指针(未被占用的位置)
    // printf("Now print the buffer stack: \n");
    // PrintStack(c, c->top);
    return ret;
}

//使缓冲栈收缩
void* lept_context_stack_shrink(lept_context* c, size_t shrunk_size) {
    assert(c->size >= shrunk_size);
    c->top -= shrunk_size;
    return c->stack + c->top;
}

//解析whitespace
static void lept_parse_whitespace(lept_context* c) {
    const char* p = c->json;
    //解析space, tab, line feed, carriage return
    while ((*p != '\0') && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')) {
        p++;
    }
    c->json = p;
}

//对 true, false, null 的合并解析
//参数表:
//  c: 保存json串的内容
//  v: 解析后保存数据的节点
//  expect_json: 期待的字符串
//  type_type: 期待的解析结果类型
static int lept_parse_literal(lept_context* context, lept_value* v, const char* expect_json, lept_type expect_type) {
    const char* expect_json_head = expect_json;  //保存 预期json文本 的字符串起始

    //尝试用 *expect_json 字面量来解析 json文本
    EXPECT(context, *expect_json);
    expect_json++;
    while ((*context->json != '\0') && (*expect_json != '\0')) {
        //若中途发生不匹配的情况, 表明 json文本 提供的字面量非法
        if (*context->json != *expect_json) {
            return LEPT_PARSE_INVALID_VALUE;
        }
        context->json++;
        expect_json++;
    }

    //若未能按照 *expect_json 完成解析，表示json字符串非法
    if (*expect_json != '\0') {
        return LEPT_PARSE_INVALID_VALUE;
    }

    //通过解析, 表明字面量解析成功, 将节点类型修改为对应字面量的类型
    v->type = expect_type;  //修改字面量的类型

    //已通过解析, 如果节点类型是布尔类型, 还要修改复合类型的布尔值
    if (ISBOOLEANTYPE(v)) {
        if (ISTRUE(expect_json_head)) {
            v->union_struct.boolean = 1;
        } else {
            v->union_struct.boolean = 0;
        }
    }
    return LEPT_PARSE_OK;
}

//校验 json数字格式
static int validate_number(const char* json) {
    int neg_tag = 0;   //负号标志
    int int_tag = 0;   //整数标志
    int frac_tag = 0;  //小数标志
    int exp_tag = 0;   //指数标志

    //在json数字格式中，以 + 正号开头不合法
    if (*json == '+') {
        return LEPT_PARSE_INVALID_VALUE;
    } else if (*json == '-') {
        neg_tag = 1;
        json++;
    }

    //检测整数
    if (*json == '0') {
        //如果整数部分以 0 开头, 则只能是单个0, 否则非法
        json++;
        int_tag = 1;
    } else if (ISDIGIT1TO9(*json)) {
        //若已 1~9 的数字开头, 则后续可以是任意数量的连续的 0~9 的数字
        json++;
        while (ISDIGIT(*json)) {
            json++;
        }
        int_tag = 1;
    } else {
        // json数字格式中, 不含整数部分是不合法的
        return LEPT_PARSE_INVALID_VALUE;
    }

    //检测小数部分
    if (*json == '.') {
        json++;
        if (!ISDIGIT(*json)) {
            return LEPT_PARSE_INVALID_VALUE;
        }
        while (ISDIGIT(*json)) {
            json++;
        }
        frac_tag = 1;
    }

    //检测指数部分: 以 e 或 E 开头, 后可跟 + 正号或 - 负号, 后接任意位 0~9的整数
    if (*json == 'e' || *json == 'E') {
        json++;
        if (*json == '+' || *json == '-') {
            json++;
        }
        while (ISDIGIT(*json)) {
            json++;
        }
        if (*json != '\0') {
            return LEPT_PARSE_INVALID_VALUE;
        }
        exp_tag = 1;
    }
    return LEPT_PARSE_OK;
}

// 解析json数字
static int lept_parse_number(lept_context* c, lept_value* v) {
    char* end;
    //校验数字格式
    int ret_value;
    if ((ret_value = validate_number(c->json)) != LEPT_PARSE_OK) {
        return ret_value;
    }

    errno = 0;

    // 处理成功时, 返回正确处理的浮点结果。若处理失败, 则返回0, 并令c->json = end;
    v->union_struct.number = strtod(c->json, &end);

    if (errno == ERANGE && v->union_struct.number == HUGE_VAL) {
        return LEPT_PARSE_NUMBER_TOO_BIG;
    }

    c->json = end;
    v->type = LEPT_NUMBER;
    return LEPT_PARSE_OK;
}

//解析4位十六进制数
static const char* lept_parse_hex4(const char* p, __uint16_t* uint_16) {
    const char* head = p;
    int i;
    __uint16_t value = 0;
    *uint_16 = 0;
    for (i = 0; i < 4; i++) {
        char ch = *p++;
        switch (ch) {
            case '0' ... '9': value = ch - '0'; break;
            case 'a' ... 'f': ch -= 32;
            case 'A' ... 'F': value = ch - 'A' + 10; break;
            default: i = 4; break;
        }
        // printf("\n get a hex digit: %x\n", value);
        // printf("\n*****%d\n", ((value << ((3 - i) << 2)) == 0xc));
        (*uint_16) |= (value << ((3 - i) << 2));
        // printf("\n#%d value has change to %x\n", i, *uint_16);
    }
    if (p - head < 4) {
        return NULL;
    }
    // printf("\n ret: %x\n", *uint_16);
    return p;
}

static int lept_encode_utf8(lept_context* c, __uint16_t uint_16) {
    switch (uint_16) {
        // 7位码点, 1字节
        case 0x0000 ... 0x007f:
            OutPutByte(uint_16);  //取7位码点, 由于该case中最高位符合固定的0, 故可取完整的一个字节
            break;

        // 11位码点, 2字节
        case 0x0080 ... 0x07ff:
            OutPutByte((0xd0 | (uint_16 >> 6)));
            OutPutByte((0x80 | (uint_16 & 0x3f)));

            break;

        //  16位码点, 3字节
        case 0x0800 ... 0xd7ff:;
        case 0xe000 ... 0xffff:
            OutPutByte((0x00e0 | ((uint_16 >> 12) & 0xff)));
            OutPutByte((0x0080 | ((uint_16 >> 6) & 0x3f)));
            OutPutByte((0x0080 | (uint_16 & 0x3f)));
            break;

        // 21位码点, 4字节
        case 0xd800 ... 0xdbff: {
            __uint16_t ui_16_low = 0;  //低代理
            const char* tmp;

            //若欠缺低代理项或低代理项的值不合法，则返回非法代理项的错误码
            if (!(tmp = lept_parse_hex4(c->json, &ui_16_low))) {
                return LEPT_PARSE_INVALID_UNICODE_SURROGATE;  // TODO:break or return?
            }

            if (ui_16_low < 0Xdc00 || ui_16_low > 0xdfff) {
                return LEPT_PARSE_INVALID_UNICODE_SURROGATE;
            }

            c->json = tmp;
            __uint32_t ui_32 = 0x10000 + (uint_16 - 0xd800) * 0x400 + (ui_16_low - 0xdc00);  //得到 U+10000 及以上的码点

            OutPutByte((0xf0 | ((ui_32 >> 18) & 0x07)));
            OutPutByte((0x80 | ((ui_32 >> 12) & 0x3f)));
            OutPutByte((0x80 | ((ui_32 >> 6) & 0x3f)));
            OutPutByte((0x80 | (ui_32 & 0x3f)));
            break;
        }
    }
}

static int lept_parse_string(lept_context* c, lept_value* v) {
    size_t head = c->top;
    EXPECT(c, '\"');  //以 " 开头, 表明这是一个字符串
    const char* p = c->json;
    int len = 0;
    __int16_t uint_16 = 0;
    int ret_state = LEPT_PARSE_OK;
    while (1) {
        char ch = *p;
        if (p != '\0') {
            p++;
        }
        switch (ch) {
            case '\"':
                len = c->top - head;
                // TODO
                // printf("Here print the stack: ");
                // PRINTSTACK(c, c->top / sizeof(__uint8_t));
                // printf("=====>");
                lept_set_string(v, (char*)lept_context_stack_shrink(c, len), len);
                c->json = p;
                return LEPT_PARSE_OK;
            case '\\': {
                const char* tmp_p = p;
                if (p) {
                    p++;
                }
                switch (*tmp_p++) {
                    case '\"': PUTC(c, '\"'); break;
                    case '\\': PUTC(c, '\\'); break;
                    case '/': PUTC(c, '/'); break;
                    case 'b': PUTC(c, '\b'); break;
                    case 'f': PUTC(c, '\f'); break;
                    case 'n': PUTC(c, '\n'); break;
                    case 'r': PUTC(c, '\r'); break;
                    case 't': PUTC(c, '\t'); break;
                    case 'u':
                        ret_state = LEPT_PARSE_OK;
                        if (!(p = lept_parse_hex4(p, &uint_16))) {}
                        c->json = p;
                        if ((ret_state = lept_encode_utf8(c, uint_16)) == LEPT_PARSE_INVALID_UNICODE_SURROGATE) {
                            return ret_state;
                        }

                        p = c->json;  //如果出现代理项，会进行第二次4位十六进制数的解析，json
                                      //文本的解析会继续推进，需要同步更新用于迭代的指针 p
                        break;
                    default:
                        c->top = head;
                        return LEPT_PARSE_INVALID_STRING_ESCAPE;
                        break;
                }
                break;  //这里的 break 不要忘记写, 否则访问后续内容就会越界
            }
                // TODO: 识别无效的非转义字符, 并抛出错误码错误码

            case '\0': c->top = head; return LEPT_PARSE_MISS_QUOTATION_MARK;
            default:
                PUTC(c, ch);  //将字符入栈
                break;
        }
    }
}

//解析 value = null / false / true
static int lept_parse_value(lept_context* c, lept_value* v) {
    switch (*c->json) {
        case 't': return lept_parse_literal(c, v, "true", LEPT_BOOLEAN);
        case 'f': return lept_parse_literal(c, v, "false", LEPT_BOOLEAN);
        case 'n': return lept_parse_literal(c, v, "null", LEPT_NULL);
        case '\"': return lept_parse_string(c, v);
        case '\0': return LEPT_PARSE_EXPECT_VALUE;  //没有value
        default: return lept_parse_number(c, v);    //其余值交由 json数字解析模块 处理
    }
}

//按照 whitespace - value - whitespace 的格式对json字符串进行解析
int lept_parse(lept_value* v, const char* json) {
    lept_context c;
    assert(v != NULL);  //节点不能是未定义的

    //对 context 的成员进行初始化
    c.json = json;
    c.stack = NULL;
    c.size = 0;  //缓冲栈大小为0
    c.top = 0;   //栈顶位置为0

    lept_init(v);               //初始化节点
    lept_parse_whitespace(&c);  //解析空白字符
    int ret_value = lept_parse_value(&c, v);

    //若value解析成功，则继续解析value之后的所有空格，再判断是否结束。若未结束则判定为多值输入
    if (ret_value == LEPT_PARSE_OK) {
        lept_parse_whitespace(&c);
        if ((ret_value == LEPT_PARSE_OK) && (*c.json != '\0')) {
            v->type = LEPT_NULL;  //多值输入，将类型强制修改为null
            return LEPT_PARSE_ROOT_NOT_SINGULAR;
        }
    }
    assert(c.top >= 0);
    // lept_free(v);
    return ret_value;
}

//返回节点的类型
lept_type lept_get_type(const lept_value* v) {
    return v->type;
}

//返回json数字
double lept_get_number(const lept_value* v) {
    assert((v != NULL) && v->type == LEPT_NUMBER);
    return v->union_struct.number;
}

const char* lept_get_string(lept_value* v) {
    assert(v != NULL && v->type == LEPT_STRING);
    return v->union_struct.str.string;
}

//为字符串动态分配内存空间, 并将写入字符串
void lept_set_string(lept_value* v, const char* string, size_t length) {
    assert((v != NULL) && (string != NULL || length == 0));
    lept_free(v);
    v->union_struct.str.string = (char*)malloc(sizeof(char) * (length + 1));  //申请新的内存空间
    memcpy(v->union_struct.str.string, string,
           length);                             //将字符串的内容在内存中按字节分配给节点
    v->union_struct.str.string[length] = '\0';  //以 空字符 结尾
    v->union_struct.str.length = length;
    v->type = LEPT_STRING;
}

//获取布尔值
int lept_get_boolean(lept_value* v) {
    assert((v != NULL) && (ISBOOLEANTYPE(v)));
    return v->union_struct.boolean;
}

//设置布尔值
void lept_set_boolean(lept_value* v, int boolean) {
    assert((v != NULL) && (ISBOOLEANTYPE(v) || v->type == LEPT_NULL));
    v->union_struct.boolean = boolean;
}

size_t lept_get_string_length(lept_value* v) {
    assert(v != NULL && v->type == LEPT_STRING);
    return v->union_struct.str.length;
}